package com.kymatrix.mpo.plus.bpm.server.controller.definition;

import cn.hutool.core.collection.CollUtil;
import com.kymatrix.mpo.plus.common.util.CollectionUtils;
import com.kymatrix.mpo.plus.bpm.server.convert.definition.BpmModelConvert;
import com.kymatrix.mpo.plus.bpm.server.flowable.entity.ModelMetaInfoEntity;
import com.kymatrix.mpo.plus.bpm.server.model.entity.definition.BpmCategoryEntity;
import com.kymatrix.mpo.plus.bpm.server.model.entity.definition.BpmFormEntity;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.ImportSaveBpmModeReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.PageQueryBpmModelReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.PageQueryBpmModelResp;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.SaveBpmModelReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.UpdateBpmModelReq;
import com.kymatrix.mpo.plus.bpm.server.model.form.model.UpdateBpmModelStateReq;
import com.kymatrix.mpo.plus.bpm.server.service.BpmCategoryService;
import com.kymatrix.mpo.plus.bpm.server.service.BpmFormService;
import com.kymatrix.mpo.plus.bpm.server.service.BpmModelService;
import com.kymatrix.mpo.plus.bpm.server.service.BpmProcessDefinitionService;
import com.kymatrix.mpo.plus.common.business.common.PageResp;
import com.kymatrix.mpo.plus.common.business.common.ResultResp;
import com.kymatrix.mpo.plus.common.util.IoUtils;
import com.kymatrix.mpo.plus.common.util.JsonUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import static com.kymatrix.mpo.plus.common.util.CollectionUtils.convertMap;
import static com.kymatrix.mpo.plus.common.util.CollectionUtils.convertSet;


@Api(tags = "BPM 流程模型相关请求处理类")
@RestController
@Validated
public class BpmModelController {

    @Resource
    private BpmModelService modelService;
    @Resource
    private BpmFormService formService;
    @Resource
    private BpmCategoryService categoryService;
    @Resource
    private BpmProcessDefinitionService processDefinitionService;

    @GetMapping("/bpm/model/page")
    @ApiOperation(value = "获得模型分页")
    public ResultResp<PageResp<PageQueryBpmModelResp>> getModelPage(PageQueryBpmModelReq pageVO) {
        PageResp<Model> pageResult = modelService.getModelPage(pageVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return ResultResp.ok(new PageResp<>());
        }

        // 拼接数据
        // 获得 Form 表单
        Set<String> formIds = convertSet(pageResult.getList(), model -> {
            ModelMetaInfoEntity metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoEntity.class);
            return metaInfo != null ? metaInfo.getFormId() : null;
        });
        Map<String, BpmFormEntity> formMap = formService.getFormMap(formIds);
        // 获得 Category Map
        Map<String, BpmCategoryEntity> categoryMap = categoryService.getCategoryMap(
                convertSet(pageResult.getList(), Model::getCategory));
        // 获得 Deployment Map
        Set<String> deploymentIds = new HashSet<>();
        pageResult.getList().forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId()));
        Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds);
        // 获得 ProcessDefinition Map
        List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
        Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);

        return ResultResp.ok(BpmModelConvert.buildModelPage(pageResult, formMap, categoryMap, deploymentMap, processDefinitionMap));
    }

    @GetMapping("/bpm/model/get")
    @ApiOperation(value = "获得模型")
    public ResultResp<PageQueryBpmModelResp> getModel(@RequestParam("id") String id) {
        Model model = modelService.getModel(id);
        if (model == null) {
            return null;
        }
        byte[] bpmnBytes = modelService.getModelBpmnXML(id);
        return ResultResp.ok(BpmModelConvert.buildModel(model, bpmnBytes));
    }

    @PostMapping("/bpm/model/create")
    @ApiOperation(value = "新建模型")
    public ResultResp<String> createModel(@Valid @RequestBody SaveBpmModelReq req) {
        return ResultResp.ok(modelService.createModel(req, null));
    }

    @PutMapping("/bpm/model/update")
    @ApiOperation(value = "修改模型")
    public ResultResp<Boolean> updateModel(@Valid @RequestBody UpdateBpmModelReq req) {
        modelService.updateModel(req);
        return ResultResp.ok(true);
    }

    @PostMapping("/bpm/model/import")
    @ApiOperation(value = "导入模型")
    public ResultResp<String> importModel(@Valid ImportSaveBpmModeReq importReq) throws IOException {
        SaveBpmModelReq createReq = new SaveBpmModelReq();
        createReq.setKey(importReq.getKey());
        createReq.setName(importReq.getName());
        createReq.setDescription(importReq.getDescription());
        
        // 读取文件
        String bpmnXml = IoUtils.readUtf8(importReq.getBpmnFile().getInputStream(), false);
        return ResultResp.ok(modelService.createModel(createReq, bpmnXml));
    }

    @PostMapping("/bpm/model/deploy")
    @ApiOperation(value = "部署模型")
    public ResultResp<Boolean> deployModel(@RequestParam("id") String id) {
        modelService.deployModel(id);
        return ResultResp.ok(true);
    }

    @PutMapping("/bpm/model/update-state")
    @ApiOperation(value = "修改模型的状态", notes = "实际更新的部署的流程定义的状态")
    public ResultResp<Boolean> updateModelState(@Valid @RequestBody UpdateBpmModelStateReq req) {
        modelService.updateModelState(req.getId(), req.getState());
        return ResultResp.ok(true);
    }

    @DeleteMapping("/bpm/model/delete")
    @ApiOperation(value = "删除模型")
    public ResultResp<Boolean> deleteModel(@RequestParam("id") String id) {
        modelService.deleteModel(id);
        return ResultResp.ok(true);
    }

}
